/*
 *                   ___====-_  _-====___
 *             _--^^^#####//      \\#####^^^--_
 *          _-^##########// (    ) \\##########^-_
 *         -############//  |\^^/|  \\############-
 *       _/############//   (@::@)   \############\_
 *      /#############((     \\//     ))#############\
 *     -###############\\    (oo)    //###############-
 *    -#################\\  / VV \  //#################-
 *   -###################\\/      \//###################-
 *  _#/|##########/\######(   /\   )######/\##########|\#_
 *  |/ |#/\#/\#/\/  \#/\##\  |  |  /##/\#/  \/\#/\#/\#| \|
 *  `  |/  V  V  `   V  \#\| |  | |/#/  V   '  V  V  \|  '
 *     `   `  `      `   / | |  | | \   '      '  '   '
 *                      (  | |  | |  )
 *                     __\ | |  | | /__
 *                    (vvv(VVV)(VVV)vvv)
 * 
 *      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * 
 *                神兽保佑            永无BUG
 */

/*
 * @Author: 火红色祥云 809880192@qq.com
 * @Date: 2022-06-27 20:57:54
 * @LastEditors: 火红色祥云 809880192@qq.com
 * @LastEditTime: 2022-10-06 21:10:57
 * @FilePath: /imx6ull-app/16_misc/misc.c
 * @Description: 杂项字符设备
 */
#include "linux/kernel.h"
#include "linux/miscdevice.h"
#include "linux/fs.h"
#include "linux/platform_device.h"
#include "linux/init.h"
#include "linux/types.h"
#include "linux/module.h"
#include "linux/of_gpio.h"
#include "linux/gpio.h"
#include "linux/of.h"
#include "linux/ide.h"

struct ST_MISCBEEP{
    struct device_node *beep_node;
    int gpio_beep;
};

struct ST_MISCBEEP st_miscbeep;

/**************************************************
* Copyright (c) 2022-2030, Lux.Co.Ltd
* filename: beep_open
* function: 
* param   : 
* return  : 
* auther  : Lux
* Date    : 2022-10-6
* Version : V1.0
**************************************************/
int beep_open(struct inode *nd, struct file *fp)
{
    fp->private_data = &st_miscbeep;
    return 0;
}

/**************************************************
* Copyright (c) 2022-2030, Lux.Co.Ltd
* filename: beep_write
* function: 
* param   : 
* return  : 
* auther  : Lux
* Date    : 2022-10-6
* Version : V1.0
**************************************************/
ssize_t beep_write(struct file *fp, const char __user *buf, size_t len, loff_t *offset)
{
    unsigned char databuf[1];
    unsigned char stat=0;
    int retval = 0;
    retval = copy_from_user(databuf,buf,len);
    if (retval < 0)
    {
        printk("data error\r\n");
        return -1;
    }
    
    stat = databuf[0];
    printk("stat:%d\r\n",stat);
    if (stat == 1)
    {
        printk("set value 0\r\n");
        gpio_set_value(st_miscbeep.gpio_beep,0);
    }
    else
    {
        printk("set value 0\r\n");
        gpio_set_value(st_miscbeep.gpio_beep,1);
    }

    return 0;
}

/**************************************************
* Copyright (c) 2022-2030, Lux.Co.Ltd
* filename: beep_release
* function: 
* param   : 
* return  : 
* auther  : Lux
* Date    : 2022-10-6
* Version : V1.0
**************************************************/
int beep_release(struct inode *nd, struct file *fp)
{
    return 0;
}
static struct file_operations fops_beep = {
    .owner = THIS_MODULE,
    .open = beep_open,
    .write = beep_write,
    .release = beep_release,
};


/*
struct miscdevice  {
	int minor;
	const char *name;
	const struct file_operations *fops;
	struct list_head list;
	struct device *parent;
	struct device *this_device;
	const struct attribute_group **groups;
	const char *nodename;
	umode_t mode;
};
*/
static struct miscdevice miscdev_beep = {
    .minor = 144,
    .name = "miscdev_beep",
    .fops = &fops_beep,
};

/**************************************************
* Copyright (c) 2022-2030, Lux.Co.Ltd
* filename: beep_probe
* function: 
* param   : 
* return  : 
* auther  : Lux
* Date    : 2022-10-6
* Version : V1.0
**************************************************/
int beep_probe(struct platform_device *pf_dev)
{
    int retval  = 0;

    printk("beep_probe\r\n");
    st_miscbeep.beep_node = of_find_node_by_path("/lux_beep");
    if (st_miscbeep.beep_node == NULL)
    {
        printk("lux_beep node not found\r\n");
        return -1;
    }

    st_miscbeep.gpio_beep = of_get_named_gpio(st_miscbeep.beep_node,"beep-gpio",0);
    if(st_miscbeep.gpio_beep < 0)
    {
        printk("gpio not found\r\n");
        return -1;
    }
    printk("gpio:%d\r\n",st_miscbeep.gpio_beep);

    retval = gpio_direction_output(st_miscbeep.gpio_beep,1);
    if (retval < 0)
    {
        printk("output set failed\r\n");
        return -1;
    }
    
    
    // misc_register(struct miscdevice *misc);
    misc_register(&miscdev_beep);
    return 0;
}

int beep_remove(struct platform_device *pf_dev)
{
    gpio_set_value(st_miscbeep.gpio_beep,1);
    misc_deregister(&miscdev_beep);
    return 0;
}
/*
struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};
*/
struct of_device_id	of_match_table[] = {
    {
		.compatible = "lux_beepgpio_compatible",
    },
    {

    },
};
static struct platform_driver beep_platform = {
    .driver = {
        .name = "lux-beep",
        .of_match_table = of_match_table,
    },
    .probe = beep_probe,
    .remove = beep_remove,
};

static int __init miscdev_beep_init(void)
{
    /*
    #define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)
extern int __platform_driver_register(struct platform_driver *,
					struct module *);
    */
    return platform_driver_register(&beep_platform);
}

static void __exit miscdev_beep_exit(void)
{
    platform_driver_unregister(&beep_platform);
}

module_init(miscdev_beep_init);
module_exit(miscdev_beep_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lux");
